#include "elalert.h"
#include <QPaintEvent>
#include <QPainter>
#include <QPropertyAnimation>
#include "elbutton.h"
#include "elicon.h"

const int ElAlert::Icon_Size = 32;
const int ElAlert::Padding_Lr = 50;
const int ElAlert::Padding_Tb = 8;
const int ElAlert::Init_Width = 200;
const int ElAlert::Icon_Text_Spacing = 5;
const int ElAlert::Title_Desc_Spacing = 5;

ElAlert::ElAlert(QWidget *parent)
    : ElComponent{parent}
{
    _icon = new ElIcon(":/icons/info.svg", this);
    _icon->fillBackground(ThemeColor::infoColor);
    initAnimation();
    initPalette();
    createCloseBtn();
    updateCloseBtn();
    auto font = _closeBtn->font();
    font.setPointSize(15);
    _closeBtn->setFont(font);
}

ElAlert::ElAlert(QWidget *parent, const QString &title, const QString &description)
    : ElAlert{parent}
{
    setTitle(title);
    setDescription(description);
}

void ElAlert::setWidth(int w)
{
    resize(w, height());
}

QString ElAlert::title() const
{
    return _title;
}

void ElAlert::setTitle(const QString &title)
{
    if (_title == title)
        return;
    _title = title;
    update();
}

QString ElAlert::description() const
{
    return _description;
}

void ElAlert::setDescription(const QString &description)
{
    if (_description == description)
        return;
    _description = description;
    update();
}

ElAlert::Type ElAlert::type() const
{
    switch (_theme.type()) {
    case ElTheme::Success:
        return Success;
    case ElTheme::Warning:
        return Warning;
    case ElTheme::Information:
        return Info;
    case ElTheme::Danger:
        return Error;
    default:
        return Info;
    }
}

void ElAlert::setType(Type type)
{
    ElTheme::Type theme_type = ElTheme::Information;
    QString icon_name = "info";
    switch (type) {
    case Success:
        theme_type = ElTheme::Success;
        icon_name = "success";
        break;
    case Warning:
        theme_type = ElTheme::Warning;
        icon_name = "warning";
        break;
    case Info:
        theme_type = ElTheme::Information;
        break;
    case Error:
        theme_type = ElTheme::Danger;
        icon_name = "error";
        break;
    default:
        break;
    }
    _theme.setType(theme_type);
    delete _icon;
    _icon = new ElIcon(QString(":/icons/%1.svg").arg(icon_name), this);
    initPalette();
    _icon->fillBackground(_palette.color(ElPalette::Foreground));
    update();
}

ElAlert::Effect ElAlert::effect() const
{
    return _effect;
}

void ElAlert::setEffect(Effect effect)
{
    if (_effect == effect)
        return;
    _effect = effect;
    initPalette();
    _icon->fillBackground(_palette.color(ElPalette::Foreground));
    updateCloseBtn();
    update();
}

bool ElAlert::isClosable() const
{
    return _closable;
}

void ElAlert::setClosable(bool closable)
{
    if (_closable == closable)
        return;
    _closable = closable;
    if (_closable) {
        createCloseBtn();
        updateCloseBtn();
    } else {
        delete _closeBtn;
        _closeBtn = nullptr;
    }
    update();
}

bool ElAlert::isCenter() const
{
    return _center;
}

void ElAlert::setCenter(bool center)
{
    if (_center == center)
        return;
    _center = center;
    update();
}

bool ElAlert::isShowIcon() const
{
    return _show_icon;
}

void ElAlert::setShowIcon(bool showIcon)
{
    if (_show_icon == showIcon)
        return;
    _show_icon = showIcon;
    update();
}

QString ElAlert::closeText() const
{
    return _close_text;
}

void ElAlert::setCloseText(const QString &closeText)
{
    _close_text = closeText;
    if (_closeBtn != nullptr) {
        auto font = _closeBtn->font();
        font.setPointSize(_close_text == "×" ? 15 : 9);
        _closeBtn->setFont(font);
        _closeBtn->setText(closeText);
    }
}

ElAlert::CloseBehavior ElAlert::closeBehavior() const
{
    return _close_behavior;
}

void ElAlert::setCloseBehavior(CloseBehavior behavior)
{
    _close_behavior = behavior;
}

void ElAlert::shut()
{
    if (_icon != nullptr) {
        auto iconAnimOpa = new QPropertyAnimation(_icon, "background", this);
        iconAnimOpa->setDuration(300);
        iconAnimOpa->setEasingCurve(QEasingCurve::OutQuad);
        auto bgColor = _palette.color(ElPalette::Foreground);
        bgColor.setAlphaF(1);
        iconAnimOpa->setStartValue(bgColor);
        bgColor.setAlphaF(0);
        iconAnimOpa->setEndValue(bgColor);
        iconAnimOpa->start();
    }
    connect(_animOpa, &QPropertyAnimation::finished, this, [=] {
        if (_close_behavior == Delete) {
            deleteLater();
        } else if (_close_behavior == KeepOn) {
            hide();
        }
        emit shutAfter();
    });
    _animOpa->start();
}

void ElAlert::paintEvent(QPaintEvent *e)
{
    QPainter painter(this);
    QRectF title_br, desc_br;
    painter.drawText(QRectF(), Qt::AlignCenter, _description, &desc_br);
    auto font = painter.font();
    font.setPointSize(10);
    font.setBold(true);
    painter.setFont(font);
    painter.drawText(QRectF(), Qt::AlignCenter, _title, &title_br);
    qreal max_br_w = title_br.width();
    if (max_br_w < desc_br.width())
        max_br_w = desc_br.width();
    auto w = 2 * Padding_Lr + max_br_w + (_show_icon ? Icon_Size + Icon_Text_Spacing : 0);
    qreal extra_space = 0;
    if (w < Init_Width) {
        extra_space = Init_Width - w;
        w = Init_Width;
    }
    auto h = 2 * Padding_Tb + title_br.height() + Title_Desc_Spacing + desc_br.height();
    resize(w, h);
    // draw rect
    painter.setPen(_palette.color(ElPalette::Border));
    painter.setBrush(_palette.color(ElPalette::Background));
    QRectF _rectf(this->rect());
    painter.drawRoundedRect(_rectf, height() / 8.0, height() / 8.0);
    // draw title
    painter.setPen(_palette.color(ElPalette::Foreground));
    auto left = Padding_Lr + (_center ? extra_space / 2.0 : 0)
                + (_show_icon ? Icon_Size + Icon_Text_Spacing : 0);
    QRectF title_drawing_rect(left, Padding_Tb, max_br_w, title_br.height());
    auto flags = Qt::AlignVCenter | (_center ? Qt::AlignHCenter : Qt::AlignLeft);
    painter.drawText(title_drawing_rect, flags, _title);
    // draw description
    auto top = Padding_Tb + title_br.height() + Title_Desc_Spacing;
    QRectF desc_drawing_rect(left, top, max_br_w, desc_br.height());
    font.setPointSize(9);
    font.setBold(false);
    painter.setFont(font);
    painter.drawText(desc_drawing_rect, flags, _description);
    // draw icon
    if (_show_icon && _icon != nullptr) {
        _icon->move(Padding_Lr, (height() - Icon_Size) / 2);
        _icon->resize(Icon_Size, Icon_Size);
        _icon->show();
    }
    // draw close button
    if (_closable && _closeBtn != nullptr) {
        _closeBtn->move(width() - _closeBtn->width() - 10, Padding_Tb);
        _closeBtn->setOpacity(_opacity);
        _closeBtn->show();
    }
    e->accept();
}

void ElAlert::initPalette()
{
    bool isLight = _effect == Light;
    _palette.setColor(ElPalette::Background, isLight ? _theme.shallowColor() : _theme.normalColor());
    _palette.setColor(ElPalette::Foreground, isLight ? _theme.normalColor() : Qt::white);
    _palette.setColor(ElPalette::Border, isLight ? _theme.shallowColor() : _theme.normalColor());
}

void ElAlert::initAnimation()
{
    _animOpa = new QPropertyAnimation(this, "opacity", this);
    _animOpa->setDuration(300);
    _animOpa->setEasingCurve(QEasingCurve::OutQuad);
    _animOpa->setStartValue(1);
    _animOpa->setEndValue(0);
}

void ElAlert::createCloseBtn()
{
    _closeBtn = new ElTextButton(_close_text, this);
    _closeBtn->setClipped(true);
    _closeBtn->hide();
    connect(_closeBtn, &ElTextButton::clicked, this, [=] {
        if (_is_repeat_click) // avoid click repeatly
            return;
        _is_repeat_click = !_is_repeat_click;
        shut();
    });
}

void ElAlert::updateCloseBtn()
{
    if (_closeBtn == nullptr)
        return;
    // change its style
    auto pal = _closeBtn->palette();
    bool isLight = _effect == Light;
    pal.setColor(ElPalette::Normal,
                 ElPalette::Foreground,
                 isLight ? ThemeColor::textDisabledColor : Qt::white);
    pal.setColor(ElPalette::Entered,
                 ElPalette::Foreground,
                 isLight ? ThemeColor::textDisabledColor : Qt::white);
    pal.setColor(ElPalette::Pressed,
                 ElPalette::Foreground,
                 isLight ? ThemeColor::textDisabledColor : Qt::white);
    _closeBtn->setPalette(pal);
}
